package com.example.util;

import com.example.entity.Host;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import server.HttpServlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;

/**
 * 0、创建 static 属性
 * private static Set<String> fileList = new HashSet<>();
 * private static int port;
 * private static Map<String, Host> hostMap = new HashMap<>();
 * 1、解析server.xml 文件获取 port、 host、appBase 信息
 * 2、根据 appBase 获取 当前目录下所有文件路径
 * 3、查找对应目录下的web.xml文件进行解析
 * 4、目标：域名--》项目名称--》servlet映射，进行信息封装
 * 5、获取web.xml中的类的路径，调用自己实现的类加载器 MyClassLoader，动态加载指定路径.class文件
 * 6、创建公共方法 向外传递 端口 和 封装的 映射信息
 *
 * @author kangshuai
 */
public class XmlHandleUtil {


    /**
     * 当前木包含所有文件的路径
     */
    private static Set<String> fileList = new HashSet<>();

    /**
     * 端口
     */
    private static int port;

    /**
     * 封装的映射信息
     */
    private static Map<String, Host> hostMap = new HashMap<>();

    public static Map<String, Host> initHostMap() throws Exception {
        serverXMLHandle();
        return hostMap;
    }

    public static int initPort() throws Exception {
        return port;
    }

    private static void serverXMLHandle() throws Exception {

        InputStream resourceAsStream = XmlHandleUtil.class.getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();


        //解析server.xml
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();
        List<Element> portNodes = rootElement.selectNodes("//Connector");
        Element element = (Element) rootElement.selectSingleNode("//Connector");
        port = Integer.parseInt(element.attributeValue("port"));

        List<Element> hostElementList = rootElement.selectNodes("//Host");

        for (Element hostElement : hostElementList) {
            //获取host
            String hostName = hostElement.attributeValue("name");
            //host对应项目路径路径
            String appBase = hostElement.attributeValue("appBase").replaceAll("\\\\", "/");
            // 项目目录 与 servlet 映射
            Map<String, Map<String, HttpServlet>> servletMapperMap = new HashMap<>();

            File file = new File(appBase);
            if (file.exists() && !file.isFile()) {
                getFile(appBase);
                File[] files = file.listFiles();
                for (File contextDir : files) {
                    if (contextDir.isDirectory()) {
                        //获取项目名称
                        String context = contextDir.getPath().split(appBase)[1].substring(1);
                        for (String filePath : fileList) {
                            if (filePath.contains(context) && filePath.contains("web.xml")) {
                                servletMapperMap.put(context, webXmlHandle(contextDir.getPath(), filePath));
                            }
                        }
                    }
                }
            }
            //封装多域名映射集
            hostMap.put(hostName, new Host(hostName, port, appBase, servletMapperMap));
            if ("localhost".equalsIgnoreCase(hostName)) {
                hostMap.put("127.0.0.1", new Host(hostName, port, appBase, servletMapperMap));
            }

        }
    }

    /**
     * 处理webXML配置文件
     *
     * @param appBase
     * @param webXmlPath
     * @return
     * @throws Exception
     */
    private static Map<String, HttpServlet> webXmlHandle(String appBase, String webXmlPath) throws Exception {

        InputStream resourceAsStreamWeb = new FileInputStream(webXmlPath);
        SAXReader saxReaderWeb = new SAXReader();
        Document documentWeb = saxReaderWeb.read(resourceAsStreamWeb);
        Element rootElementWeb = documentWeb.getRootElement();

        List<Element> selectNodes = rootElementWeb.selectNodes("//servlet");

        Map<String, HttpServlet> httpServletMap = new HashMap<>();

        for (Element selectNode : selectNodes) {

            Element servletNameElement = (Element) selectNode.selectSingleNode("servlet-name");
            String servletName = servletNameElement.getStringValue();

            Element servletClassElement = (Element) selectNode.selectSingleNode("servlet-class");

            String servletClass = servletClassElement.getStringValue();

            Element servletMapping = (Element) rootElementWeb.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");

            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
            String packageDir = appBase.replaceAll("\\\\", "/");

            MyClassLoader loader = new MyClassLoader(packageDir + "/");
            Class<?> clazz = loader.findClass(servletClass);

            httpServletMap.put(urlPattern, (HttpServlet) clazz.getClassLoader().loadClass(servletClass).getDeclaredConstructor().newInstance());
        }
        return httpServletMap;
    }

    /**
     * 获取指定目录下所有文件
     *
     * @param path
     */
    private static void getFile(String path) {
        File file = new File(path);
        File[] array = file.listFiles();
        if (array != null) {
            for (int i = 0; i < array.length; i++) {
                if (array[i].isFile()) {
                    fileList.add(array[i].getPath());
                } else if (array[i].isDirectory()) {
                    getFile(array[i].getPath());
                }
            }
        }
    }
}